package tk0084.dev.google.quiz;

import java.util.Arrays;

public class Puzzle {

	private final int _col;
	private final int _row;
	private final String _initialChars;

	public static char BLOCK = '=';
	public static char EMPTY = '0';
	private String _finalChars;
	private State _endState;

	private PuzzleStrategy _strategy = new BfsPuzzle();
	private Integer _minOrder;
	private Integer _md;
	
	public Puzzle(String initialChars, int row, int col) {
		this._initialChars = initialChars;
		this._row = row;
		this._col = col;

		_finalChars = createEndChars();

		_endState = State.end(new Table(_finalChars, _row, _col));
		
		_minOrder = createMinOrder();
	}

	public State start() {
		return _strategy.unpuzzle(this);
	}

	private String createEndChars() {
		char[] finalChars = _initialChars.replaceAll(String.valueOf(BLOCK), "").replaceAll(String.valueOf(EMPTY), "").toCharArray();
		Arrays.sort(finalChars);

		StringBuilder sb = new StringBuilder();
		for (int initialCharIndex = 0, finalCharIndex = 0; initialCharIndex < _initialChars.length() - 1; initialCharIndex++) {
			final char c = _initialChars.charAt(initialCharIndex);
			if (c == BLOCK) {
				sb.append(BLOCK);
			} else {
				sb.append(finalChars[finalCharIndex++]);
			}
		}
		sb.append(EMPTY);
		return sb.toString();
	}

	public Integer createMinOrder() {
		int minOrder = _row + _col - 2;
		int md = 0;
		for (char fromChar : _initialChars.toCharArray()) {
			if(fromChar == BLOCK){
				continue;
			}
			
			int fromIndexOf = _initialChars.indexOf(fromChar);
			int fromRowIndex = fromIndexOf/_row;
			int fromColIndex = fromIndexOf/_col;
			
			int toIndexOf = _finalChars.indexOf(fromChar);
			int toRowIndex = toIndexOf/_row;
			int toColIndex = toIndexOf/_col;
			
			int mvRow = Math.abs(fromRowIndex-toRowIndex);
			int mvCol = Math.abs(fromColIndex-toColIndex);
			
//			System.out.println(fromChar + " row:"+fromRowIndex+" col:"+fromColIndex+" toRow:"+toRowIndex+" toCol:"+toColIndex+" mvRow:"+mvRow+" mvCol"+mvCol);
			
			if((mvRow+mvCol) < minOrder){
				minOrder = mvRow+mvCol; 
			}
			md += mvRow+mvCol;
		}

		_md = md;
		return minOrder;
	}

	public String getFinalChars() {
		return _finalChars;
	}

	public String getInitialChars() {
		return _initialChars;
	}

	public int getCol() {
		return _col;
	}

	public int getRow() {
		return _row;
	}

	public boolean isEndState(State state) {
		return _endState.equals(state);
	}

	public void setStrategy(PuzzleStrategy _strategy) {
		this._strategy = _strategy;
	}

	public Integer getMinOrder() {
		return _minOrder;
	}

	public Integer getMd() {
		return _md;
	}
}
